package com.yl.list;

import lombok.extern.slf4j.Slf4j;

/**
 * 描述: 深复制|浅复制 (深拷贝|浅拷贝)
 * 1、浅拷贝：对基本数据类型进行值传递，对引用数据类型进行引用传递般的拷贝，此为浅拷贝。
 * 2、深拷贝：对基本数据类型进行值传递，对引用数据类型，创建一个新的对象，并复制其内容，此为深拷贝。
 *
 * @author: yanglin
 * @Date: 2020-06-23-9:02
 * @Version: 1.0
 */
@Slf4j
public class CloneTest {

    /**
     * 在 Java 中，所有的 Class 都继承自 Object ，而在 Object 上，存在一个 clone() 方法，
     * 它被声明为了 protected ，所以我们可以在其子类中，使用它。
     * 而无论是浅拷贝还是深拷贝，都需要实现 clone() 方法，来完成操作。
     *
     */
    public static void main(String[] args) {
        FathClass fathClassA = new FathClass();
        fathClassA.name = "张三";
        fathClassA.age= 19;
        fathClassA.childClass = new ChildClass();
        fathClassA.childClass.cName = "李四";
        fathClassA.childClass.cAge = 20;

        FathClass fathClassB = (FathClass)fathClassA.clone();

        // 深拷贝
        log.info("fathClassA == fathClassB : {}", fathClassA == fathClassB);
        log.info("fathClassA hashCode : {}", fathClassA.hashCode());
        log.info("fathClassB hashCode : {}", fathClassB.hashCode());
        log.info("fathClassA.name : {}", fathClassA.name);
        log.info("fathClassB.name : {}", fathClassB.name);
        log.info("-------------------------------------------------------");
        // 浅拷贝
        log.info("A.childClass == B.childClass : {}", fathClassA.childClass == fathClassB.childClass);
        log.info("A.childClass hashCode : {}", fathClassA.childClass.hashCode());
        log.info("B.childClass hashCode : {}", fathClassB.childClass.hashCode());


        /**
         * 深拷贝比较常用的方案有两种：
         * 序列化（serialization）这个对象，再反序列化回来，就可以得到这个新的对象，无非就是序列化的规则需要我们自己来写。
         * 继续利用 clone() 方法，既然 clone() 方法，是我们来重写的，实际上我们可以对其内的引用类型的变量，再进行一次 clone()。
         */

        /**
         * 总结
         * 实则浅拷贝和深拷贝只是相对的，如果一个对象内部只有基本数据类型，那用 clone() 方法获取到的就是这个对象的深拷贝，而如果其内部还有引用数据类型，那用 clone() 方法就是一次浅拷贝的操作。
         * 但是如果其引用数据类型也使用了clone() 方法，取到的就是这个对象的深拷贝，对于引用数据类型对象是浅拷贝。
         */
    }

    /**
     * 1.浅拷贝
     */
    static class FathClass implements Cloneable{

        public String name;

        public int age;

        ChildClass childClass;

        @Override
        protected Object clone() {
            try {
                // 浅拷贝
                FathClass fathClone = (FathClass) super.clone();
                fathClone.childClass = (ChildClass) this.childClass.clone();
                return fathClone;
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    static class ChildClass implements Cloneable{

        public String cName;

        public int cAge;

        @Override
        protected Object clone() {
            try {
                // 浅拷贝
                return super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
}
